<?php declare(strict_types=1);

/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Task\Ctl;

use Srv\Apps\Apis\Common\Ctl\StorageCtl;
use Srv\Apps\Apis\Common\DefCtl\DefStorageCategoryCtl;
use Srv\Apps\Proto\DTO\Task\TaskLotteryItemAddDTO;
use Srv\Apps\Proto\DTO\Task\TaskLotteryItemEditDTO;
use Srv\Apps\Proto\DTO\Task\TaskLotteryItemListDTO;
use Srv\Apps\Proto\Enum\YesOrNoEnum;
use Srv\Apps\Proto\VO\Task\TaskLotteryItemListVO;
use Srv\Apps\Proto\VO\Task\TaskLotteryItemVO;
use Srv\Libs\Common\CommArray;
use Srv\Libs\Common\CommString;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\AuthData;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\Page;
use Srv\Libs\Storage\DataMysql;

final class LotteryCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param int $tlyiId
     * @return array
     * getLotteryItemSrc
     */
    public function getLotteryItemSrc(int $tlyiId):array
    {
        if($tlyiId < 1) return [];
        $sql    = 'SELECT tlyi_id, tlyi_key, tlyi_text, tlyi_icon, tlyi_reward_num, tlyi_rate_num, tlyi_total_num, tlyi_status, tlyi_create_time, tlyi_update_time FROM '.$this->DbAuto->getTableNameAll('task_lottery_item').' WHERE tlyi_id='.$tlyiId.' AND tlyi_delete=0';
        $isFail = false;
        $info   = $this->DbAuto->getDataOne($sql, $isFail);
        if($isFail || !isset($info['tlyi_id'])) return [];
        return $info;
    }

    /**
     * @param array $tlyiIdList
     * @return array
     * getLotteryItemSrcBatch
     */
    public function getLotteryItemSrcBatch(array $tlyiIdList):array
    {
        if(count($tlyiIdList) < 1) return [];
        $isFail         = false;
        $list           = $this->DbAuto->getData('SELECT tlyi_id, tlyi_key, tlyi_text, tlyi_icon, tlyi_reward_num, tlyi_rate_num, tlyi_total_num, tlyi_status, tlyi_create_time, tlyi_update_time FROM '.$this->DbAuto->getTableNameAll('task_lottery_item').' WHERE tlyi_id IN('.implode(',', $tlyiIdList).') AND tlyi_delete=0', $isFail);
        $listData       = [];
        if(!$isFail && CommArray::isForeach($list)) foreach ($list as $item){
            $tlyiIdItem             = intval($item['tlyi_id']??0);
            if($tlyiIdItem < 1) continue;
            $listData[$tlyiIdItem]  = $item;
        }
        return $listData;
    }

    /**
     * @param Page $Page
     * @param array $whereData
     * @return TaskLotteryItemListVO|null
     * getLotteryItemList
     */
    public function getLotteryItemList(Page $Page, array $whereData): ?TaskLotteryItemListVO
    {
        $limitString        = $Page->getLimitString();
        $whereString        = ' WHERE tlyi_delete=0 ';
        // 检索条件
        if(count($whereData) > 0)foreach ($whereData as $key => $val){
            switch ($key){
                case TaskLotteryItemListDTO::_tlyiId:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'tlyi_id='. intval($val);
                    break;
                case TaskLotteryItemListDTO::_key:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'tlyi_key=\''.$this->DbAuto->getRealEscapeString($val).'\'';
                    break;
                case TaskLotteryItemListDTO::_text:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'tlyi_text LIKE \'%'.$this->DbAuto->getRealEscapeString($val).'%\'';
                    break;
                case TaskLotteryItemListDTO::_status:
                    $whereString    .= (strlen($whereString)>0?' AND ':'').'tlyi_status='. intval($val);
                    break;
            }
        }
        $isFail                 = false;
        $sql                    = 'SELECT SQL_CALC_FOUND_ROWS tlyi_id, tlyi_key, tlyi_text, tlyi_icon, tlyi_reward_num, tlyi_rate_num, tlyi_total_num, tlyi_status, tlyi_create_time, tlyi_update_time FROM '.$this->DbAuto->getTableNameAll('task_lottery_item').$whereString.' ORDER BY tlyi_id DESC '.$limitString;
        $list                   = $this->DbAuto->getData($sql, $isFail);
        $totalNum               = $this->DbAuto->getDataInt('SELECT FOUND_ROWS() as num', 'num');
        if($isFail) return null;
        $TaskLotteryItemVOList  = [];
        if(CommArray::isForeach($list))foreach($list as $item){
            $tlyiIdItem                 = intval($item['tlyi_id']);
            if($tlyiIdItem < 1) continue;
            $TaskLotteryItemVO          = $this->getTaskLotteryItemVO($item);
            if(!($TaskLotteryItemVO instanceof TaskLotteryItemVO)) continue;
            $TaskLotteryItemVOList[]    = $TaskLotteryItemVO;
        }
        $TaskLotteryItemListVO          = new TaskLotteryItemListVO();
        $TaskLotteryItemListVO->setList($TaskLotteryItemVOList);
        $TaskLotteryItemListVO->setPage($Page->getPageVO($totalNum));
        return $TaskLotteryItemListVO;
    }

    /**
     * @param array $info
     * @return TaskLotteryItemVO|null
     * getTaskLotteryItemVO
     */
    public function getTaskLotteryItemVO(array $info):?TaskLotteryItemVO
    {
        $tlyiId             = intval($info['tlyi_id']??0);
        if($tlyiId < 1) return null;
        $TaskLotteryItemVO  = new TaskLotteryItemVO();
        $TaskLotteryItemVO->setTlyiId($tlyiId);
        $TaskLotteryItemVO->setKey(trim($info['tlyi_key']));
        $TaskLotteryItemVO->setText(trim($info['tlyi_text']));
        $TaskLotteryItemVO->setIconUrl(StorageCtl::tag()->getStorageUrl($info['tlyi_icon'], true));
        $TaskLotteryItemVO->setRewardNum(intval($info['tlyi_reward_num']));
        $TaskLotteryItemVO->setRateStr(sprintf('%.2f', intval($info['tlyi_rate_num'])/100));
        $TaskLotteryItemVO->setTotalNum(intval($info['tlyi_total_num']));
        $TaskLotteryItemVO->setStatus(YesOrNoEnum::parseValue($info['tlyi_status']));
        $TaskLotteryItemVO->setCreateTime(intval($info['tlyi_create_time']));
        $TaskLotteryItemVO->setUpdateTime(intval($info['tlyi_update_time']));
        return $TaskLotteryItemVO;
    }

    /**
     * @param array $setData
     * @return int
     * lotteryItemAdd
     */
    public function lotteryItemAdd(array $setData):int
    {
        if(count($setData) < 1) return 0;
        $setString      = '';
        $isUpdateTask   = false;
        foreach ($setData as $key => $val){
            switch ($key){
                case TaskLotteryItemAddDTO::_text:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_text=\''.$this->DbAuto->getRealEscapeString($val).'\'';
                    break;
                case TaskLotteryItemAddDTO::_iconKey:
                    $dsacId         = DefStorageCategoryCtl::tag()->getIdByKey(DefStorageCategoryCtl::KEY_TASK_LOTTERY_ICON);
                    if($dsacId < 1) return 0;
                    $saveUrl        = StorageCtl::tag()->getStorageUrlRecord(AuthData::getLoginUserId(), $dsacId, $val);
                    if(strlen($saveUrl) < 1) return 0;
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_icon=\''.$this->DbAuto->getRealEscapeString($saveUrl).'\'';
                    break;
                case TaskLotteryItemAddDTO::_rewardNum:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_reward_num='.intval($val);
                    break;
                case TaskLotteryItemAddDTO::_rateInt:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_rate_num='.intval($val);
                    break;
                case TaskLotteryItemAddDTO::_totalNum:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_total_num='.intval($val);
                    break;
                case TaskLotteryItemAddDTO::_status:
                    $isUpdateTask   = true;
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_status='.intval($val);
                    break;
            }
        }
        if(strlen($setString) < 1) return 0;
        $currTime       = CommTime::getTimeStamp();
        $itemKey        = $this->getLotteryItemKey();
        $sql            = 'INSERT INTO '.$this->DbAuto->getTableNameAll('task_lottery_item').' SET '.$setString.', tlyi_key=\''.$this->DbAuto->getRealEscapeString($itemKey).'\', tlyi_delete=0, tlyi_create_time='.$currTime.', tlyi_update_time='.$currTime;
        $tlyiId         = $this->DbAuto->getDataId($sql);
        $tlyiId > 0 && $isUpdateTask && TaskCtl::tag()->updateTaskLotteryVersion();
        return $tlyiId;
    }

    /**
     * @param int $tlyiId
     * @param array $setData
     * @return bool
     * lotteryItemEdit
     */
    public function lotteryItemEdit(int $tlyiId, array $setData):bool
    {
        if($tlyiId < 1 || count($setData) < 1) return false;
        $setString      = '';
        foreach ($setData as $key => $val){
            switch ($key){
                case TaskLotteryItemEditDTO::_text:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_text=\''.$this->DbAuto->getRealEscapeString($val).'\'';
                    break;
                case TaskLotteryItemEditDTO::_iconKey:
                    $dsacId         = DefStorageCategoryCtl::tag()->getIdByKey(DefStorageCategoryCtl::KEY_TASK_LOTTERY_ICON);
                    if($dsacId < 1) return false;
                    $saveUrl        = StorageCtl::tag()->getStorageUrlRecord(AuthData::getLoginUserId(), $dsacId, $val);
                    if(strlen($saveUrl) < 1) return false;
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_icon=\''.$this->DbAuto->getRealEscapeString($saveUrl).'\'';
                    break;
                case TaskLotteryItemEditDTO::_rewardNum:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_reward_num='.intval($val);
                    break;
                case TaskLotteryItemEditDTO::_rateInt:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_rate_num='.intval($val);
                    break;
                case TaskLotteryItemEditDTO::_totalNum:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_total_num='.intval($val);
                    break;
                case TaskLotteryItemEditDTO::_status:
                    $setString      .= (strlen($setString) > 0?', ':'').'tlyi_status='.intval($val);
                    break;
            }
        }
        if(strlen($setString) < 1) return false;
        $currTime       = CommTime::getTimeStamp();
        $itemKey        = $this->getLotteryItemKey();
        $sql            = 'UPDATE '.$this->DbAuto->getTableNameAll('task_lottery_item').' SET '.$setString.', tlyi_key=\''.$this->DbAuto->getRealEscapeString($itemKey).'\', tlyi_update_time='.$currTime.' WHERE tlyi_id='.$tlyiId.' AND tlyi_delete=0';
        $result         = $this->DbAuto->getDataNum($sql)>0;
        $result && TaskCtl::tag()->updateTaskLotteryVersion();
        return $result;
    }

    /**
     * @return string
     * getLotteryItemKey
     */
    private function getLotteryItemKey():string
    {
        $minLength          = 8;        // 最小长度
        $maxLength          = 16;       // 最大长度
        $maxNum             = 200;
        $currNum            = 1;
        $indexNum           = 1;
        $itemKey            = CommString::genRandStr($minLength);
        while($currNum <= $maxNum){
            $tlyiIdFind     = $this->DbAuto->getDataInt('SELECT tlyi_id FROM '.$this->DbAuto->getTableNameAll('task_lottery_item').' WHERE binary tlyi_key=\''.$this->DbAuto->getRealEscapeString($itemKey).'\'', 'tlyi_id');
            if($tlyiIdFind < 1) break;
            if($indexNum >= 50){                // 失败自增长度1
                $indexNum   = 0;
                $minLength  += 1;
            }
            if($minLength > $maxLength) break;  // 长度封顶
            $itemKey        = CommString::genRandStr($minLength);
            ++$indexNum;
            ++$currNum;
        }
        return $itemKey;
    }
}